﻿
using System;

namespace MathService.Functions
{
    using Function = Func<double, double>;

    public static class FunctionsExtentions
    {
        public struct FuncValue
        {
            public double Pos;
            public double Value;

            public FuncValue(double pos, double value)
            {
                Pos = pos;
                Value = value;
            }

            public static implicit operator double(FuncValue fv) { return fv.Value; }
        }


        public struct FuncMinMaxValue
        {
            public FuncValue Min;
            public FuncValue Max;

            public FuncMinMaxValue(FuncValue min, FuncValue max)
            {
                Min = min;
                Max = max;
            }
        }

        public static double[] GetValues(this Function f, double x1, double x2, double dx)
        {
            var X = x2 - x1;
            var N = (int)Math.Abs(X / dx);
            var values = new double[N];
            for(var i = 0; i < N; i++)
                values[i] = i * dx + x1;
            return values;
        }

        public static FuncMinMaxValue GetMinMax(this Function f, double x1, double x2, double dx = 0.0001)
        {
            var values = f.GetValues(x1, x2, dx);
            var N = values.Length;
            var MinMax = new FuncMinMaxValue
                         {
                             Min = new FuncValue { Value = double.PositiveInfinity },
                             Max = new FuncValue { Value = double.NegativeInfinity }
                         };

            for(var i = 0; i < N; i++)
            {
                var v = values[i];
                if(v < MinMax.Min.Value)
                {
                    MinMax.Min.Value = v;
                    MinMax.Min.Pos = i * dx + x1;
                }
                if(v > MinMax.Max.Value)
                {
                    MinMax.Max.Value = v;
                    MinMax.Max.Pos = i * dx + x1;
                }
            }

            return MinMax;
        }

        public static FuncValue GetMinValue(this Function f, double x1, double x2, double dx = 0.0001)
        {
            var values = f.GetValues(x1, x2, dx);
            var N = values.Length;
            var min = new FuncValue { Value = double.PositiveInfinity };
            for(var i = 0; i < N; i++)
            {
                var v = values[i];
                if(v >= min.Value) continue;
                min.Value = v;
                min.Pos = i * dx + x1;
            }
            return min;
        }

        public static FuncValue GetMaxValue(this Function f, double x1, double x2, double dx = 0.0001)
        {
            var values = f.GetValues(x1, x2, dx);
            var N = values.Length;
            var max = new FuncValue { Value = double.NegativeInfinity };
            for(var i = 0; i < N; i++)
            {
                var v = values[i];
                if(v <= max.Value) continue;
                max.Value = v;
                max.Pos = i * dx + x1;
            }
            return max;
        }
    }
}
